import utils from '../utils/index.js';
import _ from 'lodash';
import unzipper from 'unzipper';

const logger = utils.Logger.getLogger('predict_3m');

const defineKline3MModel = async (db, DataTypes) => {
  return db.define('klines_3M', {
    symbol: {
      type: DataTypes.CHAR(60),
      allowNull: false,
      primaryKey: true,
    },
    open_time: {
      type: DataTypes.BIGINT(13).UNSIGNED,
      allowNull: false,
      defaultValue: 0,
      primaryKey: true,
    },
    open: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    high: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    low: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    close: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    close_time: {
      type: DataTypes.BIGINT(13).UNSIGNED,
      allowNull: false,
      defaultValue: 0,
    },
    quote_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    count: {
      type: DataTypes.INTEGER.UNSIGNED,
      allowNull: false,
      defaultValue: 0,
    },
    taker_buy_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
    taker_buy_quote_volume: {
      type: DataTypes.DECIMAL(18, 8),
      allowNull: false,
      defaultValue: 0,
    },
  }, {
    timestamps: false,
    freezeTableName: true,
  });
};

const Kline3M = utils.DB.defineModel(defineKline3MModel);

const downloadAndExtractFile =  (url) => new Promise(async (resolve, reject) => {
  try {
    const response = await fetch(url);
    if (!response.ok) {
      throw new Error(`下载文件失败: ${response.statusText}`);
    }
    const buffer = await response.arrayBuffer();
    const unzipStream = unzipper.Parse();
    unzipStream.on('entry', (entry) => {
      const chunks = [];
      entry.on('data', (chunk) => chunks.push(chunk));
      entry.on('end', () => {
        const fileContent = Buffer.concat(chunks);
        resolve(fileContent.toString('utf-8'));
      });
    });
    unzipStream.end(Buffer.from(buffer));

  } catch (error) {
    reject(error);
  }
});

const syncSymbol = async (symbol, date) => {
  logger.info(`开始下载 ${symbol} 的 ${date} 数据`);
  const url = `https://data.binance.vision/data/futures/um/daily/klines/${symbol}/3m/${symbol}-3m-${date}.zip`;
  const file = await downloadAndExtractFile(url);
  const lines = file.split('\n');
  const headers = lines[0].split(',');
  const data = lines.slice(1).map(line => line.split(','));
  // 过滤掉空行和无效行，直接结构赋值，避免重复引用 line
  const klines = data
    .filter(line => line.length >= 11 && line[0]) // 保证每行数据完整且有 open_time
    .map(([open_time, open, high, low, close, volume, close_time, quote_volume, count, taker_buy_volume, taker_buy_quote_volume]) => ({
      symbol,
      open_time,
      open,
      high,
      low,
      close,
      volume,
      close_time,
      quote_volume,
      count,
      taker_buy_volume,
      taker_buy_quote_volume,
    }));
  // 插入数据库
  const Kline3MModel = await Kline3M;
  await Kline3MModel.bulkCreate(klines, {
    ignoreDuplicates: true,
  });
  return klines;
};


(async () => {
  logger.info('Logger initialized for predict_3m');
  const symbols = ['1000000BOBUSDT','1000000MOGUSDT','1000BONKUSDC','1000BONKUSDT','1000BTTCUSDT','1000CATUSDT','1000CHEEMSUSDT','1000FLOKIUSDT','1000LUNCBUSD','1000LUNCUSDT','1000PEPEUSDC','1000PEPEUSDT','1000RATSUSDT','1000SATSUSDT','1000SHIBBUSD','1000SHIBUSDC','1000SHIBUSDT','1000WHYUSDT','1000XECUSDT','1000XUSDT','1INCHUSDT','1MBABYDOGEUSDT','AAVEUSDC','AAVEUSDT','ACEUSDT','ACHUSDT','ACTUSDT','ACXUSDT','ADABUSD','ADAUSDC','ADAUSDT','AERGOUSDT','AERGOUSDTSETTLED','AEROUSDT','AEVOUSDT','AGIXBUSD','AGIXUSDT','AGLDUSDT','AGTUSDT','AI16ZUSDT','AINUSDT','AIOTUSDT','AIUSDT','AIXBTUSDT','AKROUSDT','AKTUSDT','ALCHUSDT','ALGOUSDT','ALICEUSDT','ALPACAUSDT','ALPHAUSDT','ALPINEUSDT','ALTUSDT','AMBBUSD','AMBUSDT','ANCBUSD','ANCUSDT','ANIMEUSDT','ANKRUSDT','ANTUSDT','APEBUSD','APEUSDT','API3USDT','APTBUSD','APTUSDT','ARBUSDC','ARBUSDT','ARCUSDT','ARKMUSDT','ARKUSDT','ARPAUSDT','ARUSDT','ASRUSDT','ASTRUSDT','ATAUSDT','ATHUSDT','ATOMUSDT','AUCTIONBUSD','AUCTIONUSDT','AUDIOUSDT','AUSDT','AVAAIUSDT','AVAUSDT','AVAXBUSD','AVAXUSDC','AVAXUSDT','AWEUSDT','AXLUSDT','AXSUSDT','B2USDT','B3USDT','BABYUSDT','BADGERUSDT','BAKEUSDT','BALUSDT','BANANAS31USDT','BANANAUSDT','BANDUSDT','BANKUSDT','BANUSDT','BATUSDT','BBUSDT','BCHUSDC','BCHUSDT','BDXNUSDT','BEAMXUSDT','BELUSDT','BERAUSDT','BICOUSDT','BIDUSDT','BIGTIMEUSDT','BIOUSDT','BLUEBIRDUSDT','BLURUSDT','BLZUSDT','BMTUSDT','BNBBUSD','BNBUSDC','BNBUSDT','BNTUSDT','BNXUSDT','BNXUSDTSETTLED','BOMEUSDC','BOMEUSDT','BONDUSDT','BRETTUSDT','BROCCOLI714USDT','BROCCOLIF3BUSDT','BRUSDT','BSVUSDT','BSWUSDT','BTCBUSD','BTCBUSD_210129','BTCBUSD_210226','BTCDOMUSDT','BTCSTUSDT','BTCUSDC','BTCUSDT','BTCUSDT_210326','BTCUSDT_210625','BTCUSDT_210924','BTCUSDT_211231','BTCUSDT_220325','BTCUSDT_220624','BTCUSDT_220930','BTCUSDT_221230','BTCUSDT_230331','BTCUSDT_230630','BTCUSDT_230929','BTCUSDT_231229','BTCUSDT_240329','BTCUSDT_240628','BTCUSDT_240927','BTCUSDT_241227','BTCUSDT_250328','BTCUSDT_250627','BTCUSDT_250926','BTCUSDT_251226','BTSUSDT','BTTUSDT','BULLAUSDT','BUSDT','BZRXUSDT','C98USDT','CAKEUSDT','CATIUSDT','CELOUSDT','CELRUSDT','CETUSUSDT','CFXUSDT','CGPTUSDT','CHESSUSDT','CHILLGUYUSDT','CHRUSDT','CHZUSDT','CKBUSDT','COCOSUSDT','COMBOUSDT','COMPUSDT','COOKIEUSDT','COSUSDT','COTIUSDT','COWUSDT','CROSSUSDT','CRVUSDC','CRVUSDT','CTKUSDT','CTKUSDTSETTLED','CTSIUSDT','CUSDT','CVCUSDT','CVCUSDTSETTLED','CVXBUSD','CVXUSDT','CVXUSDTSETTLED','CYBERUSDT','DARUSDT','DASHUSDT','DEEPUSDT','DEFIUSDT','DEGENUSDT','DEGOUSDT','DENTUSDT','DEXEUSDT','DFUSDT','DGBUSDT','DIAUSDT','DMCUSDT','DODOBUSD','DODOUSDT','DODOXUSDT','DOGEBUSD','DOGEUSDC','DOGEUSDT','DOGSUSDT','DOLOUSDT','DOODUSDT','DOTBUSD','DOTECOUSDT','DOTUSDT','DRIFTUSDT','DUSDT','DUSKUSDT','DYDXUSDT','DYMUSDT','EDUUSDT','EGLDUSDT','EIGENUSDT','ENAUSDC','ENAUSDT','ENJUSDT','ENSUSDT','EOSUSDT','EPICUSDT','EPTUSDT','ERAUSDT','ESPORTSUSDT','ETCBUSD','ETCUSDT','ETHBTC','ETHBUSD','ETHFIUSDC','ETHFIUSDT','ETHUSDC','ETHUSDT','ETHUSDT_210326','ETHUSDT_210625','ETHUSDT_210924','ETHUSDT_211231','ETHUSDT_220325','ETHUSDT_220624','ETHUSDT_220930','ETHUSDT_221230','ETHUSDT_230331','ETHUSDT_230630','ETHUSDT_230929','ETHUSDT_231229','ETHUSDT_240329','ETHUSDT_240628','ETHUSDT_240927','ETHUSDT_241227','ETHUSDT_250328','ETHUSDT_250627','ETHUSDT_250926','ETHUSDT_251226','ETHWUSDT','FARTCOINUSDT','FETUSDT','FHEUSDT','FIDAUSDT','FILBUSD','FILUSDC','FILUSDT','FIOUSDT','FISUSDT','FLMUSDT','FLOWUSDT','FLUXUSDT','FOOTBALLUSDT','FORMUSDT','FORTHUSDT','FRONTUSDT','FTMBUSD','FTMUSDT','FTTBUSD','FTTUSDT','FUNUSDT','FUSDT','FXSUSDT','GALABUSD','GALAUSDT','GALBUSD','GALUSDT','GASUSDT','GHSTUSDT','GLMRUSDT','GLMUSDT','GMTBUSD','GMTUSDT','GMXUSDT','GOATUSDT','GPSUSDT','GRASSUSDT','GRIFFAINUSDT','GRTUSDT','GTCUSDT','GUNUSDT','GUSDT','HAEDALUSDT','HBARUSDC','HBARUSDT','HEIUSDT','HFTUSDT','HIFIUSDT','HIGHUSDT','HIPPOUSDT','HIVEUSDT','HMSTRUSDT','HNTUSDT','HOMEUSDT','HOOKUSDT','HOTUSDT','HUMAUSDT','HUSDT','HYPERUSDT','HYPEUSDT','ICNTUSDT','ICPBUSD','ICPUSDT','ICPUSDT_SETTLED','ICXUSDT','IDEXUSDT','IDOLUSDT','IDUSDT','ILVUSDT','IMXUSDT','INITUSDT','INJUSDT','IOSTUSDT','IOTAUSDT','IOTXUSDT','IOUSDT','IPUSDC','IPUSDT','JASMYUSDT','JELLYJELLYUSDT','JOEUSDT','JSTUSDT','JTOUSDT','JUPUSDT','KAIAUSDT','KAITOUSDC','KAITOUSDT','KASUSDT','KAVAUSDT','KDAUSDT','KEEPUSDT','KERNELUSDT','KEYUSDT','KLAYUSDT','KMNOUSDT','KNCUSDT','KOMAUSDT','KSMUSDT','LAUSDT','LAYERUSDT','LDOBUSD','LDOUSDT','LENDUSDT','LEVERBUSD','LEVERUSDT','LINAUSDT','LINKBUSD','LINKUSDC','LINKUSDT','LISTAUSDT','LITUSDT','LOKAUSDT','LOOMUSDT','LPTUSDT','LQTYUSDT','LRCUSDT','LSKUSDT','LTCBUSD','LTCUSDC','LTCUSDT','LUMIAUSDT','LUNA2BUSD','LUNA2USDT','LUNABUSD','LUNAUSDT','MAGICUSDT','MANAUSDT','MANTAUSDT','MASKUSDT','MATICBUSD','MATICUSDC','MATICUSDT','MAVIAUSDT','MAVIAUSDTSETTLED','MAVUSDT','MBLUSDT','MBOXUSDT','MDTUSDT','MELANIAUSDT','MEMEFIUSDT','MEMEUSDT','MERLUSDT','METISUSDT','MEUSDT','MEWUSDT','MILKUSDT','MINAUSDT','MINAUSDTSETTLED','MKRUSDT','MLNUSDT','MOCAUSDT','MOODENGUSDT','MORPHOUSDT','MOVEUSDT','MOVRUSDT','MTLUSDT','MUBARAKUSDT','MUSDT','MYROUSDT','MYXUSDT','NEARBUSD','NEARUSDC','NEARUSDT','NEIROETHUSDT','NEIROUSDT','NEOUSDC','NEOUSDT','NEWTUSDT','NFPUSDT','NILUSDT','NKNUSDT','NMRUSDT','NOTUSDT','NTRNUSDT','NULSUSDT','NUUSDT','NXPCUSDT','OBOLUSDT','OCEANUSDT','OGNUSDT','OGUSDT','OLUSDT','OMGUSDT','OMNIUSDT','OMUSDT','ONDOUSDT','ONEUSDT','ONGUSDT','ONTUSDT','OPUSDT','ORBSUSDT','ORCAUSDT','ORDIUSDC','ORDIUSDT','OXTUSDT','PARTIUSDT','PAXGUSDT','PENDLEUSDT','PENGUUSDC','PENGUUSDT','PEOPLEUSDT','PERPUSDT','PHAUSDT','PHBBUSD','PHBUSDT','PIPPINUSDT','PIXELUSDT','PLUMEUSDT','PNUTUSDC','PNUTUSDT','POLUSDT','POLYXUSDT','PONKEUSDT','POPCATUSDT','PORT3USDT','PORTALUSDT','POWRUSDT','PROMPTUSDT','PROMUSDT','PUFFERUSDT','PUMPBTCUSDT','PUMPUSDT','PUMPUSDTSETTLED','PUNDIXUSDT','PYTHUSDT','QNTUSDT','QTUMUSDT','QUICKUSDT','RADUSDT','RAREUSDT','RAYSOLUSDT','RAYUSDT','RDNTUSDT','REDUSDT','REEFUSDT','REIUSDT','RENDERUSDT','RENUSDT','RESOLVUSDT','REZUSDT','RIFUSDT','RLCUSDT','RNDRUSDT','RONINUSDT','ROSEUSDT','RPLUSDT','RSRUSDT','RUNEUSDT','RVNUSDT','SAFEUSDT','SAGAUSDT','SAHARAUSDT','SANDBUSD','SANDUSDT','SANTOSUSDT','SCRTUSDT','SCRUSDT','SCUSDT','SEIUSDT','SFPUSDT','SHELLUSDT','SIGNUSDT','SIRENUSDT','SKATEUSDT','SKLUSDT','SKYAIUSDT','SLERFUSDT','SLPUSDT','SLPUSDTSETTLED','SNTUSDT','SNXUSDT','SOLBUSD','SOLUSDC','SOLUSDT','SOLVUSDT','SONICUSDT','SOONUSDT','SOPHUSDT','SPELLUSDT','SPKUSDT','SPXUSDT','SQDUSDT','SRMUSDT','SSVUSDT','STEEMUSDT','STGUSDT','STMXUSDT','STORJUSDT','STOUSDT','STPTUSDT','STRAXUSDT','STRKUSDT','STXUSDT','SUIUSDC','SUIUSDT','SUNUSDT','SUPERUSDT','SUSDT','SUSHIUSDT','SWARMSUSDT','SWELLUSDT','SXPUSDT','SXTUSDT','SYNUSDT','SYRUPUSDT','SYSUSDT','TACUSDT','TAGUSDT','TAIKOUSDT','TANSSIUSDT','TAOUSDT','TAUSDT','THETAUSDT','THEUSDT','TIAUSDC','TIAUSDT','TLMBUSD','TLMUSDT','TLMUSDTSETTLED','TNSRUSDT','TOKENUSDT','TOMOUSDT','TONUSDT','TRBUSDT','TREEUSDT','TROYUSDT','TRUMPUSDC','TRUMPUSDT','TRUUSDT','TRXBUSD','TRXUSDT','TSTUSDT','TURBOUSDT','TUSDT','TUTUSDT','TWTUSDT','UMAUSDT','UNFIUSDT','UNIBUSD','UNIUSDC','UNIUSDT','USDCUSDT','USTCUSDT','USUALUSDT','UXLINKUSDT','VANAUSDT','VANRYUSDT','VELODROMEUSDT','VELVETUSDT','VETUSDT','VICUSDT','VIDTUSDT','VINEUSDT','VIRTUALUSDT','VOXELUSDT','VTHOUSDT','VVVUSDT','WALUSDT','WAVESBUSD','WAVESUSDT','WAXPUSDT','WCTUSDT','WIFUSDC','WIFUSDT','WLDUSDC','WLDUSDT','WOOUSDT','WUSDT','XAIUSDT','XCNUSDT','XEMUSDT','XLMUSDT','XMRUSDT','XRPBUSD','XRPUSDC','XRPUSDT','XTZUSDT','XVGUSDT','XVSUSDT','YFIIUSDT','YFIUSDT','YGGUSDT','ZECUSDT','ZENUSDT','ZEREBROUSDT','ZETAUSDT','ZILUSDT','ZKJUSDT','ZKUSDT','ZORAUSDT','ZRCUSDT','ZROUSDT','ZRXUSDT']
  // 获取 2025-01-01 到 2025-07-19 之间的所有日期
  const startDate = new Date('2024-07-20');
  const endDate = new Date('2025-08-01');
  const dates = [];
  while (startDate <= endDate) {
    dates.push(startDate.toISOString().split('T')[0]);
    startDate.setDate(startDate.getDate() + 1);
  }
  for (const date of dates) {
    for (const symbol of symbols) {
      try {
        await syncSymbol(symbol, date);
      } catch (error) {
        logger.error(`下载或解压文件失败: ${error}, symbol: ${symbol}, date: ${date}`);
      }
    }
  }
})();
